<?php
/**
 * MLEPP - ManiaLive Extending Plugin Pack
 *
 * -- MLEPP Plugin --
 * @name Add/Remove Tracks
 * @date 26-06-2011
 * @version r842
 * @website mlepp.trackmania.nl
 * @package MLEPP
 *
 * @author Max "TheM" Klaversma <maxklaversma@gmail.com>
 *         Petri "reaby" Järvisalo <petri.jarvisalo@mbnet.fi>
 * @copyright 2010 - 2011
 *
 * ---------------------------------------------------------------------
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will b e useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 * ---------------------------------------------------------------------
 * You are allowed to change things or use this in other projects, as
 * long as you leave the information at the top (name, date, version,
 * website, package, author, copyright) and publish the code under
 * the GNU General Public License version 3.
 * ---------------------------------------------------------------------
 */

namespace ManiaLivePlugins\MLEPP\AddRemoveTracks;

use ManiaLive\Data\Storage;
use ManiaLive\Utilities\Console;
use ManiaLive\PluginHandler\Dependency;
use ManiaLive\Features\ChatCommand\Command;
use ManiaLive\Event\Dispatcher;

use ManiaLive\Gui\Windowing\WindowHandler;
use ManiaLive\Gui\Windowing\Windows\Info;

use ManiaLivePlugins\MLEPP\Core\Core;
use ManiaLivePlugins\MLEPP\Core\Mlepp;

use ManiaLivePlugins\MLEPP\AddRemoveTracks\Events\onTrackAdded;
use ManiaLivePlugins\MLEPP\AddRemoveTracks\Events\onTrackRemoved;

class AddRemoveTracks extends \ManiaLive\PluginHandler\Plugin {

	private $mlepp;

    /**
     * onInit()
     * Function called on initialisation of ManiaLive.
     *
     * @return void
     */

    function onInit() {
        $this->setVersion(842);
        $this->setPublicMethod('getVersion');
        $dependency = new Dependency('MLEPP\Admin', 251);
        $this->addDependency($dependency);

        //ML Repository
        if(Core::RepositoryId != null){
            $this->setRepositoryId(Core::RepositoryId);
            $this->setRepositoryVersion(Core::RepositoryVersion);
        }

    }

    /**
     * onLoad()
     * Function called on loading of ManiaLive.
     *
     * @return void
     */

    function onLoad() {
        Console::println('['.date('H:i:s').'] [MLEPP] Plugin: Add/Remove Tracks r'.$this->getVersion().' by TheM & reaby.');
		$this->mlepp = Mlepp::getInstance();
        if($this->isPluginLoaded('MLEPP\Admin', 251)) {
            $this->callPublicMethod('MLEPP\Admin', 'addAdminCommand', array($this,'addlocal'), array("add","local"), true, false, false);
            $this->callPublicMethod('MLEPP\Admin', 'addAdminCommand', array($this,'addtmx'), array("add","tmx"), true,true, false);
            $this->callPublicMethod('MLEPP\Admin', 'addAdminCommand', array($this,'remove'), array("remove"), true, false, false);
        } else {
            Console::println('['.date('H:i:s').'] [MLEPP] [AddRemoveTracks] Disabled admin commands, Admin is not loaded, define admin plugin before this!');
        }
    }

	function onUnLoad() {
        Console::println('['.date('H:i:s').'] [UNLOAD] Add/Remove Tracks r'.$this->getVersion().'');
        if($this->isPluginLoaded('MLEPP\Admin', 251)) {
            $this->callPublicMethod('MLEPP\Admin', 'removeAdminCommand', 'add');   //remove t full add command structure
            $this->callPublicMethod('MLEPP\Admin', 'removeAdminCommand', 'remove'); // remove full remove command structure
	          Console::println('['.date('H:i:s').'] [UNLOAD] [AddRemoveTracks] Removed all dependend add/rmove commands from admin.');
			}
			parent::onUnload();

    }


    /**
     * addlocal()
     * Function adding track in tracklist from local source.
     *
     * @param mixed $fromLogin
     * @param mixed $param1
     * @param mixed $param2
     * @param mixed $param3
     * @return
     */

    function addlocal($fromLogin, $param1 = NULL, $param2 = NULL, $param3 = NULL) {
            if (! $this->mlepp->AdminGroup->hasPermission($fromLogin,'addLocalTrack')) {
                 $this->mlepp->sendChat(Core::$adminPermissionError,$fromLogin);
                 return;
             }
        $admin = Storage::GetInstance()->getPlayerObject($fromLogin);
        $login = $admin->login;

        if(!is_string($param1)) {
            $this->mlepp->sendChat(' %adminerror%/admin add local takes a filename as a parameter.', $admin);
            Console::println('['.date('H:i:s').'] [MLEPP] [AddRemoveTracks] ['.$admin->login.'] Missing parameter . . .');
            return;
        }

        $dataDir = $this->connection->gameDataDirectory();
        $dataDir = str_replace('\\','/',$dataDir);
        $challengeDir = $dataDir."Tracks/Challenges/";

        // autosense for file extension
        $targetFile = false;
        if(is_file($challengeDir.$param1.".Challenge.gbx")) {
            $targetFile = $challengeDir.$param1.".Challenge.gbx";
        }

        if(is_file($challengeDir.$param1.".Challenge.Gbx")) {
            $targetFile = $challengeDir.$param1.".Challenge.Gbx";
        }

        $isTmx = false;
        if($targetFile !== false) {
            $this->connection->insertChallenge($targetFile);
            $this->mlepp->sendChat('%adminaction%Admin '.$admin->nickName.'$z$s%adminaction% added new local track %variable%'.$param1);
            Console::println('['.date('H:i:s').'] [MLEPP] [AddRemoveTracks] ['.$admin->login.'] Added new local track :'.$param1);
            $eventTargetFile =  "Challenges/".$targetFile;
            Dispatcher::dispatch(new onTrackAdded($login, $eventTargetFile, $isTmx));
			$this->callPublicMethod('MLEPP\Admin', 'saveMatchSettings', $fromLogin, NULL, NULL, true);
        } else {
            $this->mlepp->sendChat(' %adminerror%File %variable%'.$param1.'.Challenge.Gbx %adminerror% at location %variable%'.$challengeDir.' adminerror%doesn\'t exist.', $admin);
            Console::println('['.date('H:i:s').'] [MLEPP] [AddRemoveTracks] ['.$admin->login.'] Tried to add new local track :'.$param1. ', but it doesn\'t exist.');
        }
    }

    /**
     * addtmx()
     * Function adding track in tracklist from TMX.
     *
     * @param mixed $fromLogin
     * @param mixed $param1
     * @param mixed $param2
     * @param mixed $param3
     * @return
     */

    function addtmx($fromLogin, $param1, $param2, $param3 = NULL) {
          if (! $this->mlepp->AdminGroup->hasPermission($fromLogin,'addTmxTrack')) {
                 $this->mlepp->sendChat(Core::$adminPermissionError,$fromLogin);
                 return;
             }
        $admin = Storage::GetInstance()->getPlayerObject($fromLogin);
        $login = $admin->login;

        if(empty($param2)) {
            $param2 = 'tmnf';
        }
		// remove casesensitivity
		$param2 = strtolower($param2);

        if($param2 != "tmn" && $param2 != "tmu" && $param2 != "tmnf") {
            $this->mlepp->sendChat(' %adminerror%Invalid TMX section, valid values are %variable%tmn, tmu and tmnf', $admin);
            Console::println('['.date('H:i:s').'] [MLEPP] [AddRemoveTracks] ['.$admin->login.'] Invalid TMX section, valid values: tmn, tmu and tmnf');
            return;
        }

        if(empty($param1)) {
            $this->mlepp->sendChat(' %adminerror%Invalid parameter count for adding TMX track.',$admin);
            Console::println('['.date('H:i:s').'] [MLEPP] [AddRemoveTracks] ['.$admin->login.'] Invalid parameter count for adding TMX track.');
            return;
        }

		if(!is_numeric($param1)) {
            $this->mlepp->sendChat(' %adminerror%You have entered a non-numeric value for tmx track. All tmx tracks are numerical.',$admin);
            Console::println('['.date('H:i:s').'] [MLEPP] [AddRemoveTracks] ['.$admin->login.'] Use of non-numeric value for TMX track.');
            return;
		}

        if($param2 == "tmu") {
            $url = "http://united.tm-exchange.com/";
        } elseif($param2 == "tmnf") {
            $url = "http://tmnforever.tm-exchange.com/";
        } elseif($param2 == "tmn") {
            $url = "http://nations.tm-exchange.com/";
        }

        $id =(string)$param1;
        $id = trim($id);
        $file =	$this->getData($url.'apiget.aspx?action=apitrackinfo&id='.$id);
        $data = explode("\t",$file);

        if(count($data) < 2) {
            $this->mlepp->sendChat(' %adminerror%Track not found on TMX.',$admin);
            Console::println('['.date('H:i:s').'] [MLEPP] [AddRemoveTracks] ['.$admin->login.'] Track not found on TMX.');
            return;
        }

        $filename = $this->filterName($data[1]);
        $id = (string)$param1;
        $id = trim($id);
        $trackdata = $this->getData($url.'get.aspx?action=trackgbx&id='.$id);
        $dataDir = $this->connection->gameDataDirectory();
        $dataDir = str_replace('\\','/',$dataDir);
        $challengeDir = $dataDir."Tracks/Challenges/TMX/";
        if(!is_dir($challengeDir)) {
            mkdir($challengeDir, "0493", true);
        }

		if(strlen($trackdata) >= 256 * 1024) {
            $size = round(strlen($trackdata) / 1024);
            $this->mlepp->sendChat(' %adminerror%The trackfile size is %variable%'.$size.'kb%adminerror%, which exceeds the limit of 256kb. Track not added.', $admin);
            Console::println('['.date('H:i:s').'] [MLEPP] [AddRemoveTracks] ['.$admin->login.'] Trackfile is too large ('.$size.'Kb > 256Kb).');
            return;
		}

        $targetFile = $challengeDir.$filename.'-'.$data[0].'.Challenge.Gbx';
        $eventTargetFile =  "Challenges/TMX/".$filename.'-'.$data[0].'.Challenge.Gbx';

        if(file_put_contents($targetFile,$trackdata) === false) {
            $this->mlepp->sendChat(' %adminerror%Couldn\'t write trackdata. Check directory- & filepermissions at dedicated tracks folder!', $admin);
            Console::println('['.date('H:i:s').'] [MLEPP] [AddRemoveTracks] ['.$admin->login.'] Trackdata couldn\'t been written. Check directory- and filepermissions!.');
            return;
        }

		$newChallenge = $this->connection->getChallengeInfo($targetFile);
		foreach($this->storage->challenges as $chal) {
			if($chal->uId == $newChallenge->uId) {
				$this->mlepp->sendChat('%adminerror% The track you tried to add is already in serverlist.');
                Console::println('['.date('H:i:s').'] [MLEPP] [AddRemoveTracks] ['.$admin->login.'] Track already in the tracklist.');
				return;
			}
		}
        $this->connection->insertChallenge($targetFile);
        $this->mlepp->sendChat('%adminaction%Admin '.$admin->nickName.'$z$s%adminaction% added track %variable%'.$data[1].'$z$s%adminaction% from $fff TM$f00X');
        Console::println('['.date('H:i:s').'] [MLEPP] [AddRemoveTracks] ['.$admin->login.'] Succesfully added track '.$data[1].'.');
        $isTmx = true;
        $tmxInfo = $data;
        Dispatcher::dispatch(new onTrackAdded($login,$eventTargetFile,$isTmx,$param2));
        $this->callPublicMethod('MLEPP\Admin', 'saveMatchSettings', $fromLogin, NULL, NULL, true);
    }

    /**
     * removethis()
     * Function removes current track from tracklist.
     *
     * @param mixed $fromLogin
     * @param mixed $param1
     * @param mixed $param2
     * @param mixed $param3
     * @return void
     */

    function removethis($fromLogin, $param1 = NULL, $param2 = NULL, $param3 = NULL) {
          if (! $this->mlepp->AdminGroup->hasPermission($fromLogin,'removeTrack')) {
                 $this->mlepp->sendChat(Core::$adminPermissionError,$fromLogin);
                 return;
             }
        $admin = Storage::GetInstance()->getPlayerObject($fromLogin);
        $login = $admin->login;
        $challenge = $this->connection->getCurrentChallengeInfo();
        $dataDir = $this->connection->gameDataDirectory();
        $dataDir = str_replace('\\','/',$dataDir);
        $file = $challenge->fileName;
        $challengeFile = $dataDir."/Tracks/".$file;
        $this->connection->removeChallenge($challengeFile);
        $this->mlepp->sendChat('%adminaction%Admin '.$admin->nickName.'$z$s%adminaction% removed this track from playlist.');
        Console::println('['.date('H:i:s').'] [MLEPP] [AddRemoveTracks] ['.$admin->login.'] Removed current track from the tracklist.');
        Dispatcher::dispatch(new onTrackRemoved($login,$challengeFile));
        $this->callPublicMethod('MLEPP\Admin', 'saveMatchSettings', $fromLogin, NULL, NULL, true);
    }

    /**
     * remove()
     * Function removes track from the tracklist.
     *
     * @param mixed $fromLogin
     * @param mixed $param1
     * @param mixed $param2
     * @param mixed $param3
     * @return
     */

    function remove($fromLogin, $param1 = NULL, $param2 = NULL, $param3 = NULL) {
          if (! $this->mlepp->AdminGroup->hasPermission($fromLogin,'removeTrack')) {
                 $this->mlepp->sendChat(Core::$adminPermissionError,$fromLogin);
                 return;
             }
        if($param1 == 'this') {
            $this->removethis($fromLogin);
            return;
        }

        $admin = Storage::GetInstance()->getPlayerObject($fromLogin);
        $login = $admin->login;
        $data = false;

        $param1 = (int)$param1;

        if($param1 == null || !\is_int($param1) || $param1<0){
            $info = Info::Create($login);
            $info->setSize(50, 15);
            $info->setTitle('Wrong use of /admin remove #');
            $text="You need to use a valid number";
            $info->setText($text);
            $info->centerOnScreen();
            WindowHandler::showDialog($info);
            return false;
            Console::println('['.date('H:i:s').'] [MLEPP] [AddRemoveTracks] ['.$admin->login.'] Wrong use of /admin remove (use valid number).');
        }

        if($this->isPluginLoaded("MLEPP\Jukebox")) {
            $data = $this->callPublicMethod("MLEPP\Jukebox", "getJukeboxTrack",$login, $param1);
            if($data != false){
                $file = $data["challenge_file"];
                $name = $data["challenge_name"];
            }
        }

		if($data == false){
			$challenges = $this->connection->getChallengeList(-1,0);
			$file = "";
			$name = "";
			foreach($challenges as $key => $data) {
				if(($key+1) == $param1) {
					$file = $data->fileName;
					$name = $data->name;
					break;
				}
			}
		}

        $dataDir = $this->connection->gameDataDirectory();
        $dataDir = str_replace('\\','/',$dataDir);
        $challengeFile = $dataDir."Tracks/".$file;
		if(!is_file($challengeFile))  {
            $this->mlepp->sendChat('%adminerror%Target trackfile not found in filesystem. Check, that you have entered correct track id!', $admin);
            Console::println('['.date('H:i:s').'] [MLEPP] [AddRemoveTracks] ['.$admin->login.'] Target trackfile not found in filesystem.');
            return;
		}
        $this->connection->removeChallenge($challengeFile);
        $this->mlepp->sendChat('%adminaction%Admin '.$admin->nickName.'$z$s%adminaction% removed track %variable%'.$name.'$z$s%adminaction% from playlist.');
        Dispatcher::dispatch(new onTrackRemoved($login,$challengeFile));
        $this->callPublicMethod('MLEPP\Admin', 'saveMatchSettings', $fromLogin, NULL, NULL, true);
    }

    /**
     * getData()
     * Function called for getting TMX data.
     *
     * @param mixed $url
     * @return mixed $content
     */

    function getData($url) {
		$options = array('http' => array(
                         'user_agent'    => 'manialive tmx-getter',        // who am i
                         'max_redirects' => 1,              // stop after 10 redirects
                         'timeout'       => 1,             // timeout on response
                    ));
        $context = stream_context_create($options);
        return @file_get_contents($url, false, $context);
    }

    /**
     * filterName()
     * Function used to filter the tracks filename.
     *
     * @param mixed $text
     * @return string $output
     */

    function filterName($text) {
        $str = trim(utf8_decode($text));
        $output ="";
        for($i=0; $i<strlen($str); $i++) {
            $c = ord($str[$i]);
            if($c == 32 ) {
                $output .= "_";
                continue;
            } // space
            if($c >= 48 && $c <= 57) {
                $output .= chr($c);
                continue;
            }// 0-9
            if($c >= 65 && $c <= 90) {
                $output .= chr($c);
                continue;
            }// A-Z
            if($c >= 97 && $c <= 122) {
                $output .= chr($c);
                continue;
            }// a-z
            $output .= "_";
        }
        return utf8_encode($output);
    }
}

?>